<template>
  <div class="content-tree" :style="{ maxHeight: autoHeight + 'px', minHeight: autoHeight + 'px' }">
    <Tree
      checkable
      :virtual="false"
      :showLine="true"
      :show-icon="true"
      :selectable="false"
      :height="autoHeight - 45"
      :tree-data="treeDatas"
      v-model:expanded-keys="expandedKeys"
      v-model:checked-keys="checkedKeys"
    >
      <template #title="{ key, title }" :key="key">
        {{ title.text }}
        <div class="op" @click.stop="key = key">
          <Checkbox v-for="item of title.tags" v-model:checked="item.Checked">{{ item.Name }}</Checkbox>
        </div>
      </template>
    </Tree>
    <div class="btn-group">
      <Button type="primary" @click="saveRights"> <SaveOutlined /> 保存 </Button>
      <Button @click="back"> <LeftOutlined /> 返回 </Button>
    </div>
  </div>
</template>
<script setup>
  import { useStore } from 'vuex';
  import { useRouter } from 'vue-router';
  import { inject, ref, toRaw, watch, onMounted } from 'vue';
  import { Tree, Button, Checkbox } from 'ant-design-vue';
  import { SaveOutlined, LeftOutlined } from '@ant-design/icons-vue';

  const $store = useStore();
  const $router = useRouter();

  const $http = inject('$http');
  const $eventBus = inject('$eventBus');

  const autoHeight = ref(400);
  const menus = ref([]);
  const treeDatas = ref([]);
  const expandedKeys = ref([]);
  const checkedKeys = ref([]);

  const $emits = defineEmits(['saved']);
  const props = defineProps({
    id: {
      type: String
    },
    type: {
      type: String,
      default: () => 'user'
    }
  });

  watch(checkedKeys, () => {
    for (let item of menus.value) {
      if (checkedKeys.value.indexOf(item.Id + '') == -1) {
        for (let tag of item.Tags) {
          tag.Checked = false;
        }
      }
    }
  });

  watch(
    menus,
    () => {
      for (let item of menus.value) {
        if (item.Tags.findIndex(t => t.Checked) != -1) {
          checkedKeys.value.push(item.Id + '');
        }
      }
    },
    { deep: true }
  );

  function getMenus() {
    menus.value.length = 0;
    expandedKeys.value.length = 0;

    $http.get(`/api/menu/${props.type == 'user' ? 'user' : 'role'}/${props.id}/rights`).then(res => {
      menus.value = (res.datas || []).map(d => {
        d.Tags = getOperators(d);

        return d;
      });

      let roots = buildTreeDatas(menus.value);

      treeDatas.value = roots;
    });
  }

  function buildTreeDatas(datas, parentId) {
    if (!datas || datas.length == 0) {
      return [];
    }

    if (!parentId) {
      return datas
        .filter(d => !d.ParentId)
        .map(d => {
          let rs = { key: '' + d.Id, title: { text: d.Name, tags: d.Tags } };

          expandedKeys.value.push(rs.key);

          if (d.HaveRight == 1) {
            checkedKeys.value.push(rs.key);
          }

          rs.children = buildTreeDatas(datas, d.Id);

          return rs;
        });
    } else {
      return datas
        .filter(d => d.ParentId == parentId)
        .map(d => {
          let rs = { key: '' + d.Id, title: { text: d.Name, tags: d.Tags } };

          expandedKeys.value.push(rs.key);

          if (d.HaveRight == 1) {
            checkedKeys.value.push(rs.key);
          }

          rs.children = buildTreeDatas(datas, d.Id);

          return rs;
        });
    }
  }

  function getOperators(item) {
    let ops = item.Operators ? item.Operators.split(',') : [];
    let haveOps = (item.HaveOperators || '').split(',');

    let tags = ops.map(o => {
      return { Name: o, Checked: haveOps.indexOf(o) != -1 };
    });

    return tags;
  }

  function saveRights() {
    let selecteds = menus.value.filter(m => checkedKeys.value.findIndex(c => c == m.Id) != -1);

    $emits(
      'saved',
      toRaw(
        selecteds.map(m => {
          let item = {
            menuId: m.Id,
            operators: m.Tags.filter(t => t.Checked)
              .map(t => t.Name)
              .join(',')
          };

          if (props.type == 'user') {
            item.userId = props.id;
          } else {
            item.roleId = props.id;
          }

          return item;
        })
      )
    );
  }

  function back() {
    if (props.type == 'user') {
      $router.push({ path: '/rbac/users' });
    } else {
      $router.push({ path: '/rbac/roles' });
    }
  }

  onMounted(() => {
    getMenus();

    autoHeight.value = $store.state.area.content.height - 40;
    $eventBus.on('windowResizeChanged', client => (autoHeight.value = client.height - 40));
  });
</script>

<style lang="less" scoped>
  .content-tree {
    :deep(> .ant-tree) {
      width: 100%;
    }

    > div {
      text-align: center;
      padding-top: 5px;
      padding-bottom: 5px;
      background: #fff;
    }
  }

  .op {
    font-weight: bold;
    display: inline-block;

    > label {
      line-height: 1;
      margin-left: 10px;

      &:first-of-type {
        margin-left: 30px;
      }
    }
  }
</style>
